package com.glodon.paas.job.monitor.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.jms.JMSException;
import javax.jms.TextMessage;

import org.apache.commons.jexl2.Expression;
import org.apache.commons.jexl2.JexlContext;
import org.apache.commons.jexl2.JexlEngine;
import org.apache.commons.jexl2.MapContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.glodon.paas.job.model.GlobalStatus;
import com.glodon.paas.job.model.MonitorEvent;
import com.glodon.paas.job.model.MonitorStatus;
import com.glodon.paas.job.model.Task;
import com.glodon.paas.job.monitor.dao.MonitorStatusDAO;
import com.glodon.paas.job.monitor.model.MonitorQueryDTO;
import com.glodon.paas.job.util.JsonUtil;

@Service
public class MonitorStatusService {
    private static final Logger logger = LoggerFactory.getLogger(MonitorStatusService.class);

    @Autowired
    private MonitorStatusDAO monitorStatusDAO;

    public void processMonitorEvent(MonitorEvent monitorEvent) {
        String traceId = monitorEvent.getTraceId();
        String type = monitorEvent.getType();
        MonitorStatus monitorStatus;
        if (monitorEvent.isTraceIndex()) {
            List<MonitorStatus> monitorStatusList = monitorStatusDAO.getByTypeAndTraceId(type, traceId);
            int index = monitorStatusList.size() + 1;
            monitorStatus = new MonitorStatus();
            monitorStatus.setTraceIndex(index);
            monitorStatus.setCreatedTime(monitorEvent.getTime());
        } else {
            monitorStatus = monitorStatusDAO.getByTypeAndTraceIdNotIndex(type, traceId);
            if (monitorStatus == null) {
                monitorStatus = new MonitorStatus();
                monitorStatus.setCreatedTime(monitorEvent.getTime());
            }else{
            	if(monitorEvent.isStartUp()){
            		 monitorStatus.setCreatedTime(monitorEvent.getTime());
            	}
            }
            
        }
        //begin set taskId
        String taskId = (String) monitorEvent.getValues().get("taskId");
        monitorStatus.setTaskId(taskId);
        //end 
        monitorStatus.setUpdatedTime(monitorEvent.getTime());
        monitorStatus.setType(type);
        monitorStatus.setCmd(monitorEvent.getCmd());
        monitorStatus.setTraceId(traceId);
        monitorStatus.getValues().putAll(monitorEvent.getValues());
        if (monitorEvent.getCmd() != null) {
            processCmd(monitorEvent, monitorStatus);
        }
        monitorStatusDAO.save(monitorStatus);
    }

    private void processCmd(MonitorEvent event, MonitorStatus monitorStatus) {
        String cmd = event.getCmd();
        GlobalStatus globalStatus = monitorStatusDAO.getGlobalStatus();
        if (globalStatus == null)
            globalStatus = new GlobalStatus();
        JexlEngine jexl = new JexlEngine();
        JexlContext jc = new MapContext();
        jc.set("global", globalStatus.getValues());
        jc.set("status", monitorStatus.getValues());
        jc.set("service", this);
        jc.set("context", jc);
        Expression e = jexl.createExpression(cmd);
        e.evaluate(jc);
        logger.info("process cmd success: {}", cmd);
        monitorStatusDAO.save(globalStatus);
    }

    public void setStatusValue(JexlContext jc, String type, String traceId, String cmd) {
        List<MonitorStatus> status = monitorStatusDAO.getByTypeAndTraceId(type, traceId);
        List<Map<String, Object>> values = new ArrayList<Map<String, Object>>();
        for (MonitorStatus monitorStatus : status) {
            values.add(monitorStatus.getValues());
        }
        jc.set("values", values);
        JexlEngine jexl = new JexlEngine();
        Expression e = jexl.createExpression(cmd);
        e.evaluate(jc);
        for (MonitorStatus monitorStatus : status) {
            monitorStatusDAO.save(monitorStatus);
        }
    }

    public List<MonitorStatus> getByTypeAndTraceId(String type, String traceId){
    	return monitorStatusDAO.getByTypeAndTraceId(type,traceId);
    }
    
    public List<MonitorStatus> getMonitorStatus(String type) {
        return monitorStatusDAO.getByType(type);
    }

    public List<MonitorStatus> getMonitorStatus(String type, Date date) {
        return monitorStatusDAO.getByType(type, date);
    }

    public void processMesage(TextMessage textMessage) throws JMSException {
        String json = textMessage.getText();
        MonitorEvent monitorEvent = JsonUtil.jsonToObject(json, MonitorEvent.class);
        processMonitorEvent(monitorEvent);
    }

    public GlobalStatus getGlobalStatus() {
        return monitorStatusDAO.getGlobalStatus();
    }

    public void setMonitorStatusDAO(MonitorStatusDAO monitorStatusDAO) {
        this.monitorStatusDAO = monitorStatusDAO;
    }

    public List<Object[]> getJobDetailsByType(String type, String jobId, String date,int fromNum,int pageNum) {
        return monitorStatusDAO.getJobDetailsByType(type, jobId, date,fromNum,pageNum);
    }

    public List<Object[]> getTaskDetailsByType(String type, String id, String date,int fromNum,int pageNum) {
        return monitorStatusDAO.getTaskDetailsByType(type, id, date,fromNum,pageNum);
    }
    
    public List<Object[]> getJobDetailsById(String type, String id) {
        return monitorStatusDAO.getJobDetailsById(type, id);
    }
    public List<MonitorStatus> getUnavalibalAgent(int threshold){
    	return monitorStatusDAO.getUnavalibalAgent(threshold);
    }
    public int getWaitingTaskNumber(){
    	return monitorStatusDAO.getWaitingTaskNumber();
    }
    public int getAvgWaitingTime(){
    	return monitorStatusDAO.getAvgWaitingTime();
    }
    
    public List<Object[]> queryTaskList(MonitorQueryDTO taskQuery){
     	return monitorStatusDAO.queryTaskList(taskQuery);
    }
}
